package org.pc2r.game.prepare;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.pc2r.exception.PC2RException;
import org.pc2r.game.Game;
import org.pc2r.game.model.Player;
import org.pc2r.game.model.Position;
import org.pc2r.game.model.SubMarine;
import org.pc2r.protocole.EnumRequest;
import org.pc2r.protocole.RequestBuilder;
import org.pc2r.protocole.message.EmptyMessage;
import org.pc2r.protocole.message.PutShipMessage;
import org.pc2r.protocole.message.ShipMessage;

public class Positionner implements Callable<Player> {

	private Game game;
	private String player;
	private Logger logger;
	private List<Player> players;

	public Positionner(Logger logger, Game game, String player,
			List<Player> players) {
		this.game = game;
		this.player = player;
		this.logger = logger;
		this.players = players;
	}

	@Override
	public Player call() {
		List<SubMarine> marines = new ArrayList<>(7);
		ShipMessage shipMessage = new ShipMessage(1);
		try {
			sendAndSet(shipMessage, marines, 1);
			sendAndSet(shipMessage, marines, 1);
			/*sendAndSet(shipMessage, marines, 2);
			sendAndSet(shipMessage, marines, 2);
			sendAndSet(shipMessage, marines, 3);
			sendAndSet(shipMessage, marines, 3);
			sendAndSet(shipMessage, marines, 4);*/
			// La liste est utilisée par 4 threads en même temps, on évite
			// les blagues
			synchronized (this.players) {
				Player e = new Player(player, marines);
				this.players.add(e);
				e.flagSubMarines();
				return e;
			}
		} catch (IOException exception) {
			logger.log(
					Level.WARNING,
					"Le joueur "
							+ player
							+ " a eu une erreur réseau durant la phase de préparation.",
					exception);
			return null;
		}
	}

	protected void sendAndSet(ShipMessage ship, List<SubMarine> sub, int size)
			throws IOException {
		ship.setSize(size);
		sendAndReceiveShip(ship, sub);
	}

	protected void sendAndReceiveShip(ShipMessage ship, List<SubMarine> sub)
			throws IOException {
		logger.info("Envoi de la demande de positionnement du joueur " + player);
		game.send(player, ship);
		String read = game.read(player);
		try {
			logger.info("Réception de la demande de positionnement du joueur " + player + " - " + read);
			PutShipMessage parsePutShip = RequestBuilder.parsePutShip(read,
					ship.getSize());
			addSubmarine(parsePutShip, sub);
			game.send(player, new EmptyMessage(EnumRequest.OK));
		} catch (PC2RException e) {
			logger.warning(e.getMessage());
			// On lui envoie un WRONG, le joueur a fait nimp
			game.send(player, new EmptyMessage(EnumRequest.WRONG));
			// On recommence ce message jusqu'à ce qu'il envoie quelque chose de
			// valide, ou se déconnecte
			sendAndReceiveShip(ship, sub);
		}
	}

	protected void addSubmarine(PutShipMessage putship, List<SubMarine> subs)
			throws PC2RException {
		List<Position> positions = putship.getPositions();
		SubMarine subMarine = new SubMarine(positions, putship.isHorizontal());
		for (SubMarine sub : subs) {
			if (subMarine.isSuperposed(sub)) {
				throw new PC2RException(
						"Le sous marin touche une case où le joueur a déjà placé un sous-marin");
			}
		}
		logger.info("Le sous-marin de taille " + positions.size()
				+ " du joueur " + player + " est positionné en " + positions);
		subs.add(subMarine);
	}
}
